<?php
/**
 * Created by .
 * User: luogan
 * Date: 2022/1/14
 */

namespace app\admin\service;


use app\exception\AuthException;
use app\model\AdminModel;
use app\model\AuthRoleModel;
use app\model\MenuModel;
use think\facade\Cache;

class AuthMenuService extends BaseService
{
    protected $menuList = [];

    /**
     * @var string
     */
    private $auth_prefix = 'admin_auth:';

    /**
     * @var string
     */
    private $menu_prefix = 'admin_menu:';

    /**
     * @var float|int
     */
    private $expire_time = 7 * 86400;


    /**
     * 初始化当前管理员权限菜单
     * @param $adminId
     * @return bool
     */
    public function init(int $adminId)
    {
        $menuCache = $this->makeMenuCache($adminId);
        $authCache = $this->makeAuthCache($adminId);
        if ($menuCache && $authCache){
            return $menuCache;
        }
        throw new AuthException('权限菜单初始化失败！');
    }

    /**
     * 生成菜单缓存
     * @param $adminId
     * @return array
     */
    public function makeMenuCache(int $adminId)
    {
        $menuList = $this->getAdminMenuList($adminId);
        $menuCache = $this->makeVueRankMenu($menuList);//生成层级菜单
        $result = Cache::store('redis')->set($this->menu_prefix.$adminId,json_encode($menuCache),$this->expire_time);
        if (!$result){
            throw new AuthException('菜单缓存失败');
        }
        return $menuCache;
    }

    /**
     * 生成当前管理员菜单权限缓存
     * @param $adminId
     * @return array
     */
    public function makeAuthCache(int $adminId)
    {
        $menuList = $this->GetAdminMenuList($adminId);
        $authCache = $this->makeAuthCacheData($menuList);//生成权限缓存
        $result = Cache::store('redis')->set($this->auth_prefix.$adminId,json_encode($authCache),$this->expire_time);
        if (!$result){
            throw new AuthException('管理员权限缓存失败！');
        }
        return $authCache;
    }

    /**
     * 获取当前管理员菜单缓存
     * @param int $adminId
     * @return array|false|mixed|string
     */
    public function getMenuCache(int $adminId)
    {
        $menuCache =  Cache::store('redis')->get($this->menu_prefix.$adminId);
        if (!$menuCache){
            //生成菜单缓存
            $menuCache = $this->MakeMenuCache($adminId);
        }else{
            $menuCache = json_decode($menuCache);
        }
        return $menuCache;
    }

    /**
     * 获取当前管理员权限缓存
     * @param int $adminId
     * @return array|false|mixed|string
     */
    public function getAuthCache(int $adminId)
    {
        $authCache = Cache::store('redis')->get($this->auth_prefix.$adminId);
        if (!$authCache){
            //生成权限缓存
            $authCache = $this->MakeAuthCache($adminId);
        }else{
            $authCache = json_decode($authCache);
        }
        return $authCache;
    }


    /**
     * 验证菜单权限
     * @param $adminID
     * @param $action
     * @return bool
     */
    public function checkAuth($adminID,$action){

        $auth = $this->getAuthCache($adminID);
        foreach ($auth as $k => $v) {
            if ($k == md5($action)){
                return true;
            }
        }
        throw new AuthException('没有访问权限');
    }

    /**
     * 获取当前管理员菜单列表
     * @param $adminId
     * @return \Hyperf\Database\Model\Builder[]|\Hyperf\Database\Model\Collection
     */
    private function getAdminMenuList(int $adminId)
    {
        $admin = AdminModel::find($adminId);
        if (empty($admin)){
            throw new AuthException();
        }
        //获取权限菜单id
        $allMenuIds = $this->getAllMenuIds($admin['role']);

        if (!$allMenuIds) throw new AuthException();
        if ($allMenuIds == 'all') {
            $menuList = MenuModel::where('status',0)
                ->field('id,title,icon,type,parent_id,action,component,path,module,controller,method,sort,status')
                ->order('sort','desc')
                ->select();
        } else {
            $menuList = MenuModel::where('status',0)
                ->whereIn('id',$allMenuIds)
                ->field('id,title,icon,type,parent_id,action,component,path,module,controller,method,sort,status')
                ->order('sort','desc')
                ->select();
        }
        return $menuList;
    }

    /**
     * 获取角色下所有菜单id
     * @param $role
     * @return array|string
     */
    public function getAllMenuIds(string $role)
    {
        $allMenuIds = [];
        $roles = explode(',', $role);
        if (count($roles) <= 0) throw new AuthException();
        foreach ($roles as $valRoleId) {
            $rules = AuthRoleModel::where('id', $valRoleId)->value('rules');
            if ($rules == 'all') return 'all';
            $allMenuIds = array_unique(array_merge($allMenuIds, explode(',', $rules)));
        }
        return $allMenuIds;
    }

    /**
     * 生成权限缓存
     * @param $menuList
     * @return array
     */
    private function makeAuthCacheData($menuList)
    {
        $cache = [];
        foreach ($menuList as $value) {
            $key = md5($value['action']);
            $cache[$key] = $value['title'];
        }
        return $cache;
    }

    /**
     * 生成菜单第一层级
     * @param $menuList
     * @return array
     */
    private function makeVueRankMenu(&$menuList)
    {
        if (count($menuList) > 0) {
            foreach ($menuList as $key => $value) {
                if ($value['parent_id'] == 0) {
                    $data = [];
                    $data['id'] = $value['id'];
                    $data['title'] = $value['title'];
                    $data['icon'] = $value['icon'];
                    $data['parent_id'] = $value['parent_id'];
                    $data['rank'] = 1;
                    $data['path'] = $value['path'];
                    $data['name'] = $value['action'];
                    $data['component'] = $value['component'];
                    $data['module'] = $value['module'];
                    $data['controller'] = $value['controller'];
                    $data['method'] = $value['method'];
                    $data['type'] = $value['type'];
                    $data['sort'] = $value['sort'];
                    $data['status'] = $value['status'];

                    $data['children'] = [];
                    $this->menuList[] = $data;
                    unset($menuList[$key]);
                }
            }
            $this->makeVueRankMenu2($menuList);

        }
        return $this->menuList;
    }

    /**
     * 生成菜单第二层级
     * @param $menuList
     * @return array
     */
    private function makeVueRankMenu2(&$menu_list)
    {
        foreach ($this->menuList as $key1 => $value1) {
            if (!isset($this->menuList[$key1]['children'])) {
                $this->menuList[$key1]['children'] = [];
            }
            if (count($menu_list) > 0) {
                if ($value1['rank'] == 1) {
                    foreach ($menu_list as $key2 => $value2) {
                        if ($value2['parent_id'] == $value1['id']) {
                            $data2 = [];
                            $data2['id'] = $value2['id'];
                            $data2['title'] = $value2['title'];
                            $data2['icon'] = $value2['icon'];
                            $data2['parent_id'] = $value2['parent_id'];
                            $data2['rank'] = 2;
                            $data2['path'] = $value2['path'];
                            $data2['name'] = $value2['action'];
                            $data2['component'] = $value2['component'];
                            $data2['module'] = $value2['module'];
                            $data2['controller'] = $value2['controller'];
                            $data2['method'] = $value2['method'];
                            $data2['type'] = $value2['type'];
                            $data2['sort'] = $value2['sort'];
                            $data2['status'] = $value2['status'];
                            $this->menuList[$key1]['children'][] = $data2;
                            unset($menu_list[$key2]);
                        }
                    }
                }

            }

        }
        $this->makeVueRankMenu3($menu_list);
        return $this->menuList;

    }


    /**
     * 生成菜单第三层级
     * @param $menuList
     * @return array
     */
    private function makeVueRankMenu3(&$menu_list)
    {
        foreach ($this->menuList as $key1 => $value1) {
            if (isset($value1['children']) && !empty($value1['children'])) {
                foreach ($value1['children'] as $key2 => $value2) {
                    if (!isset($this->menuList[$key1]['children'][$key2]['children'])) {
                        $this->menuList[$key1]['children'][$key2]['children'] = [];
                    }
                    if ($value2['rank'] == 2) {
                        if (count($menu_list) > 0) {
                            foreach ($menu_list as $key3 => $value3) {
                                if ($value3['parent_id'] == $value2['id']) {
                                    $data3 = [];
                                    $data3['id'] = $value3['id'];
                                    $data3['title'] = $value3['title'];
                                    $data3['icon'] = $value3['icon'];
                                    $data3['parent_id'] = $value3['parent_id'];
                                    $data3['rank'] = 3;
                                    $data3['path'] = $value3['path'];
                                    $data3['name'] = $value3['action'];
                                    $data3['component'] = $value3['component'];
                                    $data3['module'] = $value3['module'];
                                    $data3['controller'] = $value3['controller'];
                                    $data3['method'] = $value3['method'];
                                    $data3['type'] = $value3['type'];
                                    $data3['sort'] = $value3['sort'];
                                    $data3['status'] = $value3['status'];
                                    $this->menuList[$key1]['children'][$key2]['children'][] = $data3;
                                    unset($menu_list[$key3]);
                                }
                            }
                        }
                    }


                }
            }
        }
        $this->makeVueRankMenu4($menu_list);
        return $this->menuList;
    }

    /**
     * 生成菜单第四层级
     * @param $menuList
     * @return array
     */
    private function makeVueRankMenu4(&$menu_list)
    {
        foreach ($this->menuList as $key1 => $value1) {
            if (isset($value1['children'])) {
                foreach ($value1['children'] as $key2 => $value2) {
                    if (isset($value2['children'])) {
                        foreach ($value2['children'] as $key3 => $value3) {
                            if (!isset($this->menuList[$key1]['children'][$key2]['children'][$key3]['children'])) {
                                $this->menuList[$key1]['children'][$key2]['children'][$key3]['children'] = [];
                            }
                            if ($value3['rank'] == 3) {
                                if (count($menu_list) > 0) {
                                    foreach ($menu_list as $key4 => $value4) {
                                        if ($value4['parent_id'] == $value3['id']) {
                                            $data4 = [];
                                            $data4['id'] = $value4['id'];
                                            $data4['title'] = $value4['title'];
                                            $data4['icon'] = $value4['icon'];
                                            $data4['action'] = $value4['action'];
                                            $data4['parent_id'] = $value4['parent_id'];
                                            $data4['rank'] = 4;
                                            $data4['path'] = $value4['path'];
                                            $data4['name'] = $value4['action'];
                                            $data4['component'] = $value4['component'];
                                            $data4['module'] = $value4['module'];
                                            $data4['controller'] = $value4['controller'];
                                            $data4['method'] = $value4['method'];
                                            $data4['type'] = $value4['type'];
                                            $data4['sort'] = $value4['sort'];
                                            $data4['status'] = $value4['status'];
                                            $this->menuList[$key1]['children'][$key2]['children'][$key3]['children'][] = $data4;
                                            unset($menu_list[$key4]);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return $this->menuList;
    }


}
